Fix: Exclude commodity of interest from reduced costs calculation for LCOX assets#882
Conversation
…costs calculation
There was a problem hiding this comment.
Pull Request Overview
This PR fixes the reduced costs calculation for LCOX (Levelised Cost of X) assets by excluding the commodity of interest from flow revenues. The primary changes include refactoring the asset revenue calculation methods, updating the CommodityPrices type usage throughout the codebase, and removing an unused dependency.
- Adds new method
get_revenue_from_flows_for_objectivetoAssetthat considers agent objective type - Refactors
get_input_cost_from_pricesto useCommodityPricesinstead ofHashMap - Updates
ObjectiveTypewith method to determine if primary output should be excluded from reduced costs
Reviewed Changes
Copilot reviewed 9 out of 12 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/asset.rs | Adds new revenue calculation methods that consider agent objectives for LCOX assets |
| src/agent.rs | Adds helper method to determine if primary output should be excluded from reduced costs |
| src/simulation/prices.rs | Updates reduced cost calculation to use new asset method and adds utility methods to CommodityPrices |
| src/simulation/optimisation.rs | Updates function signatures to use CommodityPrices type instead of HashMap |
| src/simulation/investment.rs | Updates price handling to use CommodityPrices methods |
| Cargo.toml | Removes unused current_dir dependency |
| tests/data/simple/*.csv | Updates test data files to reflect corrected reduced cost calculations |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #882 +/- ##
==========================================
+ Coverage 85.23% 85.38% +0.14%
==========================================
Files 50 50
Lines 5317 5337 +20
Branches 5317 5337 +20
==========================================
+ Hits 4532 4557 +25
+ Misses 565 560 -5
Partials 220 220 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
I think this is probably fine for now and maybe worth merging as an intermediate. I do have some issues though. One is that this isn't truly a "reduced cost" any more, at least in terms of what that means from a linear programming perspective. If we're moving towards using this approach for all assets (candidates and existing), then I think we should stop using the term reduced cost (I always found this term confusing anyway). It's sort of an "activity cost", but: The second issue is that, as this now has to take the agent objective into account, I think we'd be better off doing this calculation within the investment algorithm. The process would be: perform dispatch -> calculate commodity prices -> pass these prices to investment algorithm -> Is there any reason this wouldn't work that I'm missing? Perhaps this would end up unnecessarily repeating calculations so we should reorder things a bit. In any case, I think we should move away from the current approach of calculating "reduced costs" within the dispatch stage and passing these to the investment algorithm, especially when the meaning of these costs can change due to agent decisions unrelated to dispatch |
|
Furthermore, at some point we're going to allow agents to have multiple objectives (maybe LCOX and NPV), so the approach here wouldn't work for that |
Happy to stop using the term... I guess if we do this, we should update the docs for consistency. What do you think about this @ahawkes?
I think the problem is that you would end up recomputing reduced costs, as you say. We could potentially move things around a bit though; maybe the code for reduced costs (or whatever we want to call them) shouldn't live in Can you elaborate on your last point? When would the meaning of the costs change?
Yes, but that's a future us problem 😉. Users can't do that now and if we decided we wanted to allow it, this would be one of the problems we'd need a solution to first. It's worth noting that the code was wrong before, so this is technically just a bugfix. |
|
Can you elaborate on your last point? When would the meaning of the costs change?
Ie that these costs do or don’t include the primary commodity depending on the agent objective
Sent from Outlook for iOS<https://aka.ms/o0ukef>
…________________________________
From: Alex Dewar ***@***.***>
Sent: Friday, October 3, 2025 5:29:49 PM
To: EnergySystemsModellingLab/MUSE_2.0 ***@***.***>
Cc: Bland, Tom ***@***.***>; Review requested ***@***.***>
Subject: Re: [EnergySystemsModellingLab/MUSE_2.0] Fix: Exclude commodity of interest from reduced costs calculation for LCOX assets (PR #882)
This email from ***@***.*** originates from outside Imperial. Do not click on links and attachments unless you recognise the sender. If you trust the sender, add them to your safe senders list<https://spam.ic.ac.uk/SpamConsole/Senders.aspx> to disable email stamping for this address.
[https://avatars.githubusercontent.com/u/23149834?s=20&v=4]alexdewar left a comment (EnergySystemsModellingLab/MUSE2#882)<#882 (comment)>
I think this is probably fine for now and maybe worth merging as an intermediate. I do have some issues though.
One is that this isn't truly a "reduced cost" any more, at least in terms of what that means from a linear programming perspective. If we're moving towards using this approach for all assets (candidates and existing), then I think we should stop using the term reduced cost (I always found this term confusing anyway). It's sort of an "activity cost", but:
Happy to stop using the term... I guess if we do this, we should update the docs for consistency. What do you think about this @ahawkes<https://github.com/ahawkes>?
The second issue is that, as this now has to take the agent objective into account, I think we'd be better off doing this calculation within the investment algorithm. The process would be: perform dispatch -> calculate commodity prices -> pass these prices to investment algorithm -> calculate_coefficients_for_lcox would take these prices and calculate an appropriate activity cost using these prices, rather than the current approach of using reduced costs (we'd need to modify activity_cost()), which in this case would ignore flows from the primary output -> I think the rest is the same.
Is there any reason this wouldn't work that I'm missing?
Perhaps this would end up unnecessarily repeating calculations so we should reorder things a bit. In any case, I think we should move away from the current approach of calculating "reduced costs" within the dispatch stage and passing these to the investment algorithm, especially when the meaning of these costs can change due to agent decisions unrelated to dispatch
I think the problem is that you would end up recomputing reduced costs, as you say. We could potentially move things around a bit though; maybe the code for reduced costs (or whatever we want to call them) shouldn't live in prices.rs.
Can you elaborate on your last point? When would the meaning of the costs change?
Furthermore, at some point we're going to allow agents to have multiple objectives (maybe LCOX and NPV), so the approach here wouldn't work for that
Yes, but that's a future us problem 😉. Users can't do that now and if we decided we wanted to allow it, this would be one of the problems we'd need a solution to first. It's worth noting that the code was wrong before, so this is technically just a bugfix.
—
Reply to this email directly, view it on GitHub<#882 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AFU73DYDVPM4FM2DQ3TPNML3V2P73AVCNFSM6AAAAACIF4N6RCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTGNRWGM3TAMJVGU>.
You are receiving this because your review was requested.Message ID: ***@***.***>
|
|
Yes please stop using the term reduced costs. Intuition is that using them will never work, judging by what we’re seeing.
Re the rest of this debate. I agree that all investment related calculations should reside in the investment part of the code. So yes, pass prices there, and then do calcs. To keep code well placed for future updates, this should work better, as future objectives can be built in the same place, manipulating prices in other ways.
________________________________
From: Tom Bland ***@***.***>
Sent: Friday, October 3, 2025 5:33:57 PM
To: EnergySystemsModellingLab/MUSE_2.0 ***@***.***>
Cc: Hawkes, Adam D ***@***.***>; Mention ***@***.***>
Subject: Re: [EnergySystemsModellingLab/MUSE_2.0] Fix: Exclude commodity of interest from reduced costs calculation for LCOX assets (PR #882)
[https://avatars.githubusercontent.com/u/23723407?s=20&v=4]tsmbland left a comment (EnergySystemsModellingLab/MUSE2#882)<#882 (comment)>
Can you elaborate on your last point? When would the meaning of the costs change?
Ie that these costs do or don’t include the primary commodity depending on the agent objective
Sent from Outlook for iOS<https://aka.ms/o0ukef>
…________________________________
From: Alex Dewar ***@***.***>
Sent: Friday, October 3, 2025 5:29:49 PM
To: EnergySystemsModellingLab/MUSE_2.0 ***@***.***>
Cc: Bland, Tom ***@***.***>; Review requested ***@***.***>
Subject: Re: [EnergySystemsModellingLab/MUSE_2.0] Fix: Exclude commodity of interest from reduced costs calculation for LCOX assets (PR #882)
This email from ***@***.*** originates from outside Imperial. Do not click on links and attachments unless you recognise the sender. If you trust the sender, add them to your safe senders list<https://spam.ic.ac.uk/SpamConsole/Senders.aspx> to disable email stamping for this address.
[https://avatars.githubusercontent.com/u/23149834?s=20&v=4]alexdewar left a comment (EnergySystemsModellingLab/MUSE2#882)<#882 (comment)>
I think this is probably fine for now and maybe worth merging as an intermediate. I do have some issues though.
One is that this isn't truly a "reduced cost" any more, at least in terms of what that means from a linear programming perspective. If we're moving towards using this approach for all assets (candidates and existing), then I think we should stop using the term reduced cost (I always found this term confusing anyway). It's sort of an "activity cost", but:
Happy to stop using the term... I guess if we do this, we should update the docs for consistency. What do you think about this @ahawkes<https://github.com/ahawkes>?
The second issue is that, as this now has to take the agent objective into account, I think we'd be better off doing this calculation within the investment algorithm. The process would be: perform dispatch -> calculate commodity prices -> pass these prices to investment algorithm -> calculate_coefficients_for_lcox would take these prices and calculate an appropriate activity cost using these prices, rather than the current approach of using reduced costs (we'd need to modify activity_cost()), which in this case would ignore flows from the primary output -> I think the rest is the same.
Is there any reason this wouldn't work that I'm missing?
Perhaps this would end up unnecessarily repeating calculations so we should reorder things a bit. In any case, I think we should move away from the current approach of calculating "reduced costs" within the dispatch stage and passing these to the investment algorithm, especially when the meaning of these costs can change due to agent decisions unrelated to dispatch
I think the problem is that you would end up recomputing reduced costs, as you say. We could potentially move things around a bit though; maybe the code for reduced costs (or whatever we want to call them) shouldn't live in prices.rs.
Can you elaborate on your last point? When would the meaning of the costs change?
Furthermore, at some point we're going to allow agents to have multiple objectives (maybe LCOX and NPV), so the approach here wouldn't work for that
Yes, but that's a future us problem 😉. Users can't do that now and if we decided we wanted to allow it, this would be one of the problems we'd need a solution to first. It's worth noting that the code was wrong before, so this is technically just a bugfix.
—
Reply to this email directly, view it on GitHub<#882 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AFU73DYDVPM4FM2DQ3TPNML3V2P73AVCNFSM6AAAAACIF4N6RCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTGNRWGM3TAMJVGU>.
You are receiving this because your review was requested.Message ID: ***@***.***>
—
Reply to this email directly, view it on GitHub<#882 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AC37JLLVHJ354QL5SJSOYCL3V2QPLAVCNFSM6AAAAACIF4N6RCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTGNRWGM4DAMZTGU>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Okey doke. What would be a good term to use instead? I suppose it's essentially profit per unit activity... (though in the LCOX case we're excluding the COI). I'll hold off on changing the terminology until we do #879 and update the docs (which also use the term "reduced costs" to describe the alternative calculation for existing assets) at the same time.
I could move the code for "not quite reduced costs" (or whatever we're calling it) to somewhere else, but I'm not sure it matters much. Bear in mind this is the first PR in a series and we'll probably reorganise things more as we go along anyway. @tsmbland In terms of separating out the calculations for LCOX and NPV, I don't think that's a good idea at this stage. Currently, assets either need the LCOX-type calculation or the NPV-type one, but not both, and we have a map that's keyed by asset, so you'll always have the right value for a given asset. Let's not overcomplicate things. |
I don't think we have to/should give this a name. It's essentially just an intermediate part of the LCOX or NPV calculation that doesn't have any meaning on its own
Sure. My idea is that we should pass prices to the investment algorithm, then calculate Maybe worth chatting about this. In the end it may be better to merge this then change it later, or maybe better to take a more direct route |
Fair enough. Put simply it's the "LCOX related total variable operating cost" - but indeed just an intermediate of LCOX, and specific to LCOX. Though - as an aside - worth noting that this "thing" we're calculating may end up being an objective in itself (e.g a lexicographic strategy that balances LCOX against total variable operating cost - i.e. it's cheap in the long term, and it's also likely to get dispatched).
I guess it's unlikely we'd have both LCOX and NPV for one agent/commodity. But for sure in future it's possible to have multiple objectives, and are combined via a decision rule, just like MUSE1. Not sure that helps here, but if it does and code can be structured for this addition accordingly that would be great.
|
@tsmbland Ohhh I see. Sorry, I hadn't clocked that... yes, that make sense. I think it probably makes sense to merge this PR in the short term though; it's a relatively simple fix as is and I'd like to try to sort out #876 ASAP. But we should open an issue about restructuring the code along those lines and circle back to it. @ahawkes Agree with what you're saying. We'll try to keep the code modular. |
Ok sounds good. I believe this is all correct so I'll approve. I'd like to do this restructuring ASAP as well, but don't want to step on your toes, so please let me know when you're done with all the "reduced costs" stuff from your side |
tsmbland
left a comment
There was a problem hiding this comment.
Looks good, with the caveats that we've discussed
|
@tsmbland: Ok let's merge this now and then if you want to create an issue for the refactoring and assign yourself to it, that'd be great! I don't think it'll conflict with anything else I'm doing right now, so feel free to crack on 😄 |
|
If you want to do both at the same time, be my guest! It probs makes more sense than trying to split them up. |
True. I guess there are two steps:
Point 2 will have to fix #879, but I can do point 1 first separately |
|
Totally up to you. If it's easy enough to do in one PR that's fine, but feel free to split up if it's getting too long or you want feedback or whatever. |
Description
This PR is the first in a series to fix the reduced costs calculation, which currently has a number of problems (see #876).
When calculating reduced costs, we should exclude the commodity of interest from the flow revenues for any assets owned by an agent whose objective type is LCOX for that year/commodity. It actually says this in the docs, but it slipped my mind when writing the code. So this is what I've done.
I first changed things so that
Assethas a method for calculating flow revenues, partly because I think that's where this calculation belongs (along withget_operating_cost) and partly because to unify the code path with the existingget_input_costs_from_pricesmethod. In order to do that, I changed theinput_pricesargument of the latter toCommodityPrices(it was aHashMap), which led to some churn as I then had to update various other bits of code. I think it probably makes sense as a change by itself anyway; it's more readable for one thing.As we need to know what agent the asset is owned by in order to know whether its objective type is LCOX, we have to pass an
AgentMapas an argument to this newget_revenue_from_flows_for_objectivemethod, which I don't really like: I think it would be cleaner if theAssetstruct just had the rightRc<Agent>stored as a field rather than anAgentID, then we wouldn't have to do a lookup. We'll need to refactorAssetin order to do #879 anyway, so it probably makes sense to hold off on that for now though. Can always do it later if there's time.Unrelated change: I noticed we had an unused dependency, so I've removed it.
Fixes #878.
Type of change
Key checklist
$ cargo test$ cargo docFurther checks